home *** CD-ROM | disk | FTP | other *** search
- /*
- * signals.c --
- *
- * Copyright 1988 Regents of the University of California.
- * Permission to use, copy, modify, and distribute this
- * software and its documentation for any purpose and without
- * fee is hereby granted, provided that the above copyright
- * notice appear in all copies. The University of California
- * makes no representations about the suitability of this
- * software for any purpose. It is provided "as is" without
- * express or implied warranty.
- *
- * This contains routines that deal with Sprite signals. See the man pages
- * on signals for an explanation of the Sprite signaling facilities. The
- * only thing that is explained in these comments is the implementation of
- * these facilities.
- *
- * SYNCHRONIZATION
- *
- * Whenever the signal state of a process is modified, the sig monitor lock
- * is usually grabbed, and the process is usually locked (e.g., LocalSend).
- * Code that doesn't obtain the sig monitor lock is in migration and
- * signals initialization (e.g., fork & exec); the process is locked in
- * these cases. Currently (18-Dec-1991) code that doesn't lock the process
- * (e.g., some calls to SigClearPendingMask) only works on the current
- * process (i.e., a process is changing its own pending signals list), and
- * is therefore unlikely to interfere with the code that didn't obtain the
- * sig monitor lock. (XXX This really ought to get cleaned up.)
- *
- * When the signal state is looked at no locking is done. It is assumed
- * that there are two ways that the signal state will be looked at:
- *
- * 1) A process in the middle of executing a system call
- * will check to see if any signals are pending before waiting for
- * an extended period (i.e. waiting for a read to complete). If
- * not then it will go to sleep until either a signal comes in or
- * the thing that it is waiting for completes. This does not
- * require any synchronization on reading because the routine
- * which is used to put a process to sleep (see Sync_WaitEventInt)
- * will check for signals with the master lock down before the
- * process is put to sleep. If there are signals pending, then
- * the sleep call will return immediately. Otherwise if a signal
- * comes in after the process goes to sleep then it will be
- * awakened by the Sig_Send which calls Sync_WakeWaitingProcess which
- * synchronizes correctly with the Sync_Wait calls. Thus there
- * is no way to miss a signal in this case.
- *
- * 2) A process is returning to user mode after trapping into the kernel
- * for some reason and it wants to see if signals are pending before
- * it returns. In this case the trap handler (see Exc_Trap) will
- * disable interrupts before checking to see if signals are pending.
- * If they are then it will enable interrupts and process the signal.
- * Otherwise it will return to user mode with interrupts being enabled
- * on the return to user mode. If a signal came in when
- * interrupts were disabled then once interrupts are enabled the
- * process will be interrupted and return back into the kernel.
- * Likewise once the user process returns to user mode if a signal is
- * delivered then the user process will be interrupted. Interruption
- * is possible of course only on a multi-processor. Once interrupted it
- * will be forced back into the kernel where it will discover a
- * signal. Thus a signal cannot be missed in this case either.
- *
- */
-
- #ifndef lint
- static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/sig/signals.c,v 9.15 92/04/10 16:42:00 kupfer Exp $ SPRITE (Berkeley)";
- #endif not lint
-
- #include <sprite.h>
- #include <stdlib.h>
- #include <sig.h>
- #include <sync.h>
- #include <dbg.h>
- #include <list.h>
- #include <proc.h>
- #include <procMigrate.h>
- #include <status.h>
- #include <sched.h>
- #include <sigInt.h>
- #include <rpc.h>
- #include <net.h>
- #include <vm.h>
- #include <bstring.h>
- #include <stdio.h>
-
- unsigned int sigBitMasks[SIG_NUM_SIGNALS];
- int sigDefActions[SIG_NUM_SIGNALS];
- int sigCanHoldMask;
-
- Sync_Lock sigLock;
- Sync_Condition signalCondition;
-
- static void LocalSend _ARGS_((Proc_ControlBlock *procPtr, int sigNum, int code,
- Address addr));
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Sig_Init --
- *
- * Initialize the signal data structures.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The set of bit masks and the set of default actions are set up.
- *
- *----------------------------------------------------------------------
- */
-
- void
- Sig_Init()
- {
- int i;
-
- Sync_LockInitDynamic(&sigLock, "Sig:sigLock");
-
- for (i = SIG_MIN_SIGNAL; i < SIG_NUM_SIGNALS; i++) {
- sigBitMasks[i] = Sig_NumberToMask(i);
- sigDefActions[i] = SIG_KILL_ACTION;
- }
-
- /*
- * Note that SIG_RESUME uses the "kill" action, even though it's not
- * actually used to kill the process.
- */
- sigDefActions[SIG_DEBUG] = SIG_DEBUG_ACTION;
- sigDefActions[SIG_ARITH_FAULT] = SIG_DEBUG_ACTION;
- sigDefActions[SIG_ILL_INST] = SIG_DEBUG_ACTION;
- sigDefActions[SIG_ADDR_FAULT] = SIG_DEBUG_ACTION;
- sigDefActions[SIG_BREAKPOINT] = SIG_DEBUG_ACTION;
- sigDefActions[SIG_TRACE_TRAP] = SIG_DEBUG_ACTION;
- sigDefActions[SIG_MIGRATE_TRAP] = SIG_MIGRATE_ACTION;
- sigDefActions[SIG_MIGRATE_HOME] = SIG_MIGRATE_ACTION;
- sigDefActions[SIG_SUSPEND] = SIG_SUSPEND_ACTION;
- sigDefActions[SIG_TTY_INPUT] = SIG_SUSPEND_ACTION;
- sigDefActions[SIG_URGENT] = SIG_IGNORE_ACTION;
- sigDefActions[SIG_CHILD] = SIG_IGNORE_ACTION;
- sigDefActions[SIG_TTY_SUSPEND] = SIG_SUSPEND_ACTION;
- sigDefActions[SIG_TTY_OUTPUT] = SIG_SUSPEND_ACTION;
- sigDefActions[SIG_IO_READY] = SIG_IGNORE_ACTION;
- sigDefActions[SIG_WINDOW_CHANGE] = SIG_IGNORE_ACTION;
-
- sigCanHoldMask =
- ~(sigBitMasks[SIG_ARITH_FAULT] | sigBitMasks[SIG_ILL_INST] |
- sigBitMasks[SIG_ADDR_FAULT] | sigBitMasks[SIG_KILL] |
- sigBitMasks[SIG_BREAKPOINT] | sigBitMasks[SIG_TRACE_TRAP] |
- sigBitMasks[SIG_MIGRATE_HOME] | sigBitMasks[SIG_SUSPEND]);
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Sig_ProcInit --
- *
- * Initialize the signal data structures for the first process.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Signal state initialized.
- *
- *----------------------------------------------------------------------
- */
- void
- Sig_ProcInit(procPtr)
- register Proc_ControlBlock *procPtr;
- {
- procPtr->sigHoldMask = 0;
- procPtr->sigPendingMask = 0;
- bcopy((Address)sigDefActions,(Address)procPtr->sigActions,
- sizeof(sigDefActions));
- bzero((Address)procPtr->sigMasks,sizeof(procPtr->sigMasks));
- bzero((Address)procPtr->sigCodes,sizeof(procPtr->sigCodes));
- procPtr->sigFlags = 0;
- }
-
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Sig_Fork --
- *
- * Copy over the parents signal state into the child.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Signal state copied from parent to child and pending mask cleared in
- * child. Migration is held until the first return into user mode.
- *
- *----------------------------------------------------------------------
- */
- void
- Sig_Fork(parProcPtr, childProcPtr)
- register Proc_ControlBlock *parProcPtr;
- register Proc_ControlBlock *childProcPtr;
- {
- /*
- * Copy the parent's signal state to the child. Set up migration
- * to be held initially. On the first return to user mode, after
- * signals are processed, migration will be reenabled.
- */
- childProcPtr->sigHoldMask = parProcPtr->sigHoldMask |
- Sig_NumberToMask(SIG_MIGRATE_TRAP);
- childProcPtr->sigPendingMask = 0;
- bcopy((Address)parProcPtr->sigActions,
- (Address)childProcPtr->sigActions,
- sizeof(childProcPtr->sigActions));
- bcopy((Address)parProcPtr->sigMasks,
- (Address)childProcPtr->sigMasks,
- sizeof(childProcPtr->sigMasks));
- bzero((Address)childProcPtr->sigCodes,sizeof(childProcPtr->sigCodes));
- childProcPtr->sigFlags = 0;
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Sig_Exec --
- *
- * Clear all signal handlers on exec. Assumed called with the proc
- * table entry locked such that signals against this process are
- * prevented.
- *
- * Results:
- * None.
- *
- * Side effects:
- * All signal handlers are cleared and the pending mask is cleared.
- *
- *----------------------------------------------------------------------
- */
- void
- Sig_Exec(procPtr)
- Proc_ControlBlock *procPtr;
- {
- register int *actionPtr;
- register int i;
-
- for (i = SIG_MIN_SIGNAL, actionPtr = &procPtr->sigActions[SIG_MIN_SIGNAL];
- i < SIG_NUM_SIGNALS;
- i++, actionPtr++) {
- if (*actionPtr > SIG_SUSPEND_ACTION) {
- /*
- * The action contains a signal handler to call. Reset back to
- * the default action.
- */
- *actionPtr = sigDefActions[i];
- procPtr->sigMasks[i] = 0;
- }
- }
- procPtr->sigPendingMask = 0;
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Sig_ChangeState --
- *
- * Set the entire signal state of the process to that given. When
- * setting the state verify that improper signals are not blocked or
- * ignored. The process is assumed to be locked.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The signal actions and hold mask will be set for the process.
- * Might change the suspend/resume flags in the PCB.
- *
- *----------------------------------------------------------------------
- */
-
- ENTRY void
- Sig_ChangeState(procPtr, actions, sigMasks, pendingMask, sigCodes, holdMask)
- register Proc_ControlBlock *procPtr;
- int actions[];
- register int sigMasks[];
- int pendingMask;
- int sigCodes[];
- int holdMask;
- {
- register int i;
- register int *actionPtr;
-
- LOCK_MONITOR;
-
- for (i = SIG_MIN_SIGNAL, actionPtr = &actions[SIG_MIN_SIGNAL];
- i < SIG_NUM_SIGNALS;
- i++, actionPtr++) {
- if (i == SIG_KILL) {
- continue;
- }
- procPtr->sigActions[i] = *actionPtr;
- if (*actionPtr == SIG_IGNORE_ACTION) {
- /*
- * If is ignore action then make sure that is not one of the
- * signals that cannot be ignored. If not then remove the signal
- * from the pending mask.
- */
- if (sigBitMasks[i] & sigCanHoldMask) {
- pendingMask &= ~sigBitMasks[i];
- } else {
- procPtr->sigActions[i] = sigDefActions[i];
- }
- } else if (*actionPtr > SIG_NUM_ACTIONS) {
- /*
- * If greater than one of the actions then must be the address
- * of a signal handler so store the signal mask.
- */
- procPtr->sigMasks[i] = sigMasks[i] & sigCanHoldMask;
- }
- }
-
- procPtr->sigPendingMask = pendingMask;
-
- /*
- * Make sure the suspend/resume flags are consistent with the pending
- * signals mask.
- */
- procPtr->genFlags &= ~PROC_RESUME_PROCESS;
- if (pendingMask & Sig_NumberToMask(SIG_SUSPEND)) {
- procPtr->genFlags |= PROC_PENDING_SUSPEND;
- } else {
- procPtr->genFlags &= ~PROC_PENDING_SUSPEND;
- }
-
- procPtr->sigHoldMask = holdMask & sigCanHoldMask;
- bcopy((Address) sigCodes, (Address) procPtr->sigCodes,
- sizeof(procPtr->sigCodes));
- procPtr->specialHandling = 1;
-
- UNLOCK_MONITOR;
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Sig_UserSend --
- * Send a signal to a process. Call the internal routine to do the
- * work.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
- ReturnStatus
- Sig_UserSend(sigNum, pid, familyID)
- int sigNum; /* The signal to send. */
- Proc_PID pid; /* The id number of the process or process
- family. */
- Boolean familyID; /* Whether the id is a process id or a process
- group id. */
- {
- return(Sig_Send(sigNum, SIG_NO_CODE, pid, familyID, (Address)0));
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * LocalSend --
- *
- * Send a signal to a process on the local machine. It assumed that the
- * process is locked down when we are called.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Signal pending mask and code modified. The process's suspend and
- * resume flags might also get changed.
- *
- *----------------------------------------------------------------------
- */
-
- ENTRY static void
- LocalSend(procPtr, sigNum, code, addr)
- register Proc_ControlBlock *procPtr;
- int sigNum;
- int code;
- Address addr;
- {
- int sigBitMask;
-
- LOCK_MONITOR;
-
- /*
- * Signals can't be sent to kernel processes unless the system is being
- * shutdown since kernel processes never get the opportunity to handle
- * signals.
- */
- if ((procPtr->genFlags & PROC_KERNEL) && !sys_ShuttingDown) {
- UNLOCK_MONITOR;
- return;
- }
-
- if ((procPtr->sigActions[sigNum] == SIG_DEBUG_ACTION) &&
- proc_KillMigratedDebugs && (procPtr->genFlags & PROC_FOREIGN)) {
- /*
- * Kill the process rather than letting it go silently into that
- * good night (on the wrong machine). Debugging migrated
- * processes is nasty. It would be nice if we could redirect
- * the printf to the process's home node, too.
- */
- sigNum = SIG_KILL;
- if (proc_MigDebugLevel > 1) {
- printf("Warning: killing a migrated process that would have gone into the debugger, pid %x rpid %x uid %d.\n",
- procPtr->processID, (int) procPtr->peerProcessID,
- procPtr->userID);
-
- }
- }
-
- /*
- * Only send the signal if it shouldn't be ignored and if it isn't
- * a signal to migrate an unmigrated process. (The latter can easily
- * happen when signalling a process family to migrate home.)
- */
- if ((procPtr->sigActions[sigNum] != SIG_IGNORE_ACTION) &&
- !((sigNum == SIG_MIGRATE_HOME) && (procPtr->peerHostID == NIL))) {
-
- if (sigNum == SIG_RESUME) {
- /*
- * Resume the suspended process.
- */
- Proc_ResumeProcess(procPtr, FALSE);
- }
- if (procPtr->sigActions[sigNum] == SIG_SUSPEND_ACTION &&
- procPtr->state == PROC_SUSPENDED) {
- /*
- * Are sending a suspend signal to a process that is already
- * suspended. In this case just notify the parent that the
- * process has been suspended. This is necessary because resume
- * signals are sent by processes to debugged processes which do not
- * really get resumed. However, the signaling process will not
- * be informed that the process it sent the signal to did not get
- * resumed (SIG_RESUME works regardless whether it actually
- * resumes anything or not). Thus a process may believe that
- * a process is running even though it really isn't and it may
- * send a suspend signal to an already suspended process.
- *
- * There is a potential race here between a process getting
- * suspended and us checking here but it doesn't matter. If
- * it gets suspended after we check then the parent will get
- * notified anyway.
- */
- Proc_InformParent(procPtr, PROC_SUSPEND_STATUS);
- } else if (sigNum != SIG_RESUME ||
- procPtr->sigActions[sigNum] != SIG_KILL_ACTION) {
- sigBitMask = sigBitMasks[sigNum];
- procPtr->sigPendingMask |= sigBitMask;
- procPtr->sigCodes[sigNum] = code;
- procPtr->sigAddr = (int)addr;
- if (sigNum == SIG_SUSPEND) {
- /*
- * Set the "pending suspend" flag in case the process is
- * resumed before it actually suspends. Clear the "resume"
- * flag in case the process is resumed and then suspended
- * again before the first suspend is processed.
- */
- procPtr->genFlags |= PROC_PENDING_SUSPEND;
- procPtr->genFlags &= ~PROC_RESUME_PROCESS;
- }
- if (procPtr->sigHoldMask & sigBitMask & ~sigCanHoldMask) {
- /*
- * We received a signal that was blocked but can't be blocked
- * by users. It only can be blocked if we are in the middle of
- * executing a signal handler for the signal. So we set things
- * up to take the default action and make the signal unblocked
- * so that we don't get an infinite loop of errors.
- */
- procPtr->sigHoldMask &= ~sigBitMask;
- procPtr->sigActions[sigNum] = sigDefActions[sigNum];
- }
- procPtr->specialHandling = 1;
- /*
- * If the process is waiting then wake it up.
- */
- Sync_WakeWaitingProcess(procPtr);
- if (sigNum == SIG_KILL || sigNum == SIG_MIGRATE_TRAP ||
- sigNum == SIG_MIGRATE_HOME) {
- if (sigNum == SIG_KILL && procPtr->state == PROC_NEW &&
- (procPtr->genFlags & PROC_FOREIGN)) {
- /*
- * The process was only partially created. We can't make
- * it runnable so we have to reclaim it directly.
- * Do this in the background so that
- * Proc_DestroyMigratedProc has to wait for Sig_Send
- * to unlock the process and we avoid a race condition.
- */
- Proc_CallFunc(Proc_DestroyMigratedProc,
- (ClientData) procPtr->processID, 0);
- } else {
- /*
- * Resume the process so that we can perform the signal.
- * If we're killing it, we tell Proc_ResumeProcess so it
- * will even wake up a debugged process.
- */
- Proc_ResumeProcess(procPtr,
- (sigNum == SIG_KILL) ? TRUE : FALSE);
- }
- }
- }
- }
- UNLOCK_MONITOR;
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Sig_SendProc --
- *
- * Store the signal in the pending mask and store the code for the given
- * process. The code and addr are passed to the user interrupt
- * handler. The code indicates the cause of the signal. The addr
- * indicates the address of the fault.
- *
- * NOTE: Assumes that we are called without the master lock down and
- * with the process locked.
- *
- * Results:
- * In the case of a local process, SUCCESS is returned. If the process
- * is migrated, error conditions such as RPC_TIMEOUT may be returned.
- *
- * Side effects:
- * Signal pending mask and code modified. If the process being signalled
- * is migrated, an RPC is sent. If the process is local, the sched_Mutex
- * master lock is grabbed.
- *
- *----------------------------------------------------------------------
- */
- ReturnStatus
- Sig_SendProc(procPtr, sigNum, code, addr)
- register Proc_ControlBlock *procPtr;
- int sigNum;
- int code;
- Address addr;
- {
- ReturnStatus status;
-
- /*
- * Make sure that the signal is in range.
- */
- if (sigNum < SIG_MIN_SIGNAL || sigNum >= SIG_NUM_SIGNALS) {
- if (sigNum == 0) {
- return(SUCCESS);
- } else {
- return(SIG_INVALID_SIGNAL);
- }
- }
-
- /*
- * Handle migrated processes specially. There's a race condition
- * when sending a signal to a migrated process, since it can
- * migrate back to this host while we're doing it. Therefore,
- * if the problem was that the process didn't exist, check
- * to see if it has migrated back to this host (it's no longer MIGRATED).
- * We don't have to check for MIGRATING, since SigMigSend waits for
- * a migration in progress to complete. Also make sure that while the
- * signal is sent and the process is unlocked, it processID doesn't change.
- */
- if (procPtr->state == PROC_MIGRATED ||
- (procPtr->genFlags & PROC_MIGRATING)) {
- Proc_PID processID;
- processID = procPtr->processID;
- status = SigMigSend(procPtr, sigNum, code, addr);
- if (processID != procPtr->processID) {
- return(status);
- }
- if ((status != PROC_INVALID_PID) ||
- (procPtr->state == PROC_MIGRATED)) {
- return(status);
- }
- }
- if (procPtr->state == PROC_EXITING) {
- return(PROC_INVALID_PID);
- } else if (procPtr->state == PROC_NEW) {
- if (procPtr->genFlags & PROC_FOREIGN && proc_MigDebugLevel > 0) {
- printf("Warning: got signal for process %x before migration complete.\n",
- procPtr->processID);
- }
- return(PROC_INVALID_PID);
- } else {
- LocalSend(procPtr, sigNum, code, addr);
- return(SUCCESS);
- }
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Sig_Send --
- *
- * Send a signal to a process. This entails marking the signal into
- * the signal pending mask for the process and waking up the process
- * if it is asleep.
- *
- * Results:
- * An error is the signal or the process id are invalid. SUCCESS
- * otherwise.
- *
- * Side effects:
- * The signal information in the proc table for the process that
- * is being sent the signal may be modified.
- *
- *----------------------------------------------------------------------
- */
-
- ReturnStatus
- Sig_Send(sigNum, code, id, familyID, addr)
- int sigNum; /* The signal to send. */
- int code; /* The code that goes with the signal. */
- Proc_PID id; /* The id number of the process or process
- family. */
- Boolean familyID; /* Whether the id is a process id or a process
- group id. */
- Address addr; /* The address of the fault */
- {
- register Proc_ControlBlock *procPtr;
- Proc_PCBLink *procLinkPtr;
- ReturnStatus status;
- List_Links *familyList;
- int userID;
- int hostID;
-
- if (!Proc_ComparePIDs(id, PROC_MY_PID)) {
- hostID = Proc_GetHostID(id);
- if (hostID != rpc_SpriteID) {
- /*
- * Send a remote signal.
- */
- if (hostID == NET_BROADCAST_HOSTID ||
- hostID > NET_NUM_SPRITE_HOSTS || hostID < 0) {
- return(PROC_INVALID_PID);
- } else {
- return(SigSendRemoteSignal(hostID, sigNum, code, id,
- familyID, addr));
- }
- }
- }
- /*
- * Get the pointer to the control block if this is a valid process id.
- */
- if (!familyID) {
- if (Proc_ComparePIDs(id, PROC_MY_PID)) {
- procPtr = Proc_GetEffectiveProc();
- if (procPtr == (Proc_ControlBlock *) NIL) {
- panic("Sig_Send: procPtr == NIL\n");
- }
- Proc_Lock(procPtr);
- } else {
- procPtr = Proc_LockPID(id);
- if (procPtr == (Proc_ControlBlock *) NIL) {
- return(PROC_INVALID_PID);
- }
- if (!Proc_HasPermission(procPtr->effectiveUserID)) {
- Proc_Unlock(procPtr);
- return(PROC_UID_MISMATCH);
- }
- }
- status = Sig_SendProc(procPtr, sigNum, code, addr);
- Proc_Unlock(procPtr);
- } else {
- Proc_PID *pidArray;
- int i;
- int numProcs;
-
- status = Proc_LockFamily((int)id, &familyList, &userID);
- if (status != SUCCESS) {
- return(status);
- }
- if (!Proc_HasPermission(userID)) {
- Proc_UnlockFamily((int)id);
- return(PROC_UID_MISMATCH);
- }
-
- /*
- * Send a signal to everyone in the given family. We do this
- * by grabbing a list of process IDs and then sending the signals
- * with the family not locked, to avoid deadlocks resulting from
- * signals being sent with the family locked.
- */
-
- numProcs = 0;
- LIST_FORALL(familyList, (List_Links *) procLinkPtr) {
- numProcs++;
- }
- pidArray = (Proc_PID *) malloc(numProcs * sizeof(Proc_PID));
- i = 0;
- LIST_FORALL(familyList, (List_Links *) procLinkPtr) {
- procPtr = procLinkPtr->procPtr;
- Proc_Lock(procPtr);
- pidArray[i] = procPtr->processID;
- Proc_Unlock(procPtr);
- i++;
- if (i > numProcs) {
- panic("Sig_Send: process family changed size while locked.\n");
- free((Address) pidArray);
- return(FAILURE);
- }
- }
- Proc_UnlockFamily((int)id);
- for (i = 0; i < numProcs; i++) {
- procPtr = Proc_LockPID(pidArray[i]);
- if (procPtr == (Proc_ControlBlock *) NIL) {
- /*
- * Race condition: process got removed.
- */
- continue;
- }
- status = Sig_SendProc(procPtr, sigNum, code, addr);
- Proc_Unlock(procPtr);
- if (status != SUCCESS) {
- break;
- }
- }
- free((Address) pidArray);
- }
-
- return(status);
- }
-
- typedef struct {
- int sigNum;
- int code;
- Proc_PID id;
- Boolean familyID;
- int effUid;
- Address addr;
- } SigParms;
-
-
- /*
- *----------------------------------------------------------------------
- *
- * SigSendRemoteSignal --
- *
- * Send a signal to a process on a remote machine.
- *
- * Results:
- * Return the status from the remote machine.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- ReturnStatus
- SigSendRemoteSignal(hostID, sigNum, code, id, familyID, addr)
- int hostID; /* Host to send message to. */
- int sigNum; /* Signal to send. */
- int code; /* Code to send. */
- Proc_PID id; /* ID to send it to. */
- Boolean familyID; /* TRUE if are sending to a process family. */
- Address addr; /* Address of signal. */
- {
- SigParms sigParms;
- Rpc_Storage storage;
- Proc_ControlBlock *procPtr;
-
- sigParms.sigNum = sigNum;
- sigParms.code = code;
- sigParms.id = id;
- sigParms.familyID = familyID;
- procPtr = Proc_GetEffectiveProc();
- sigParms.effUid = procPtr->effectiveUserID;
- sigParms.addr = addr;
-
- storage.requestParamPtr = (Address)&sigParms;
- storage.requestParamSize = sizeof(sigParms);
- storage.requestDataPtr = (Address)NIL;
- storage.requestDataSize = 0;
- storage.replyParamPtr = (Address)NIL;
- storage.replyParamSize = 0;
- storage.replyDataPtr = (Address)NIL;
- storage.replyDataSize = 0;
-
- return(Rpc_Call(hostID, RPC_SIG_SEND, &storage));
-
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Sig_RpcSend --
- *
- * Stub to handle a remote signal RPC.
- *
- * Results:
- * SUCCESS.
- *
- * Side effects:
- * Reply is sent.
- *
- *----------------------------------------------------------------------
- */
- /*ARGSUSED*/
- ReturnStatus
- Sig_RpcSend(srvToken, clientID, command, storagePtr)
- ClientData srvToken; /* Handle on server process passed to
- * Rpc_Reply */
- int clientID; /* Sprite ID of client host */
- int command; /* Command identifier */
- register Rpc_Storage *storagePtr; /* The request fields refer to the
- * request buffers and also indicate
- * the exact amount of data in the
- * request buffers. The reply fields
- * are initialized to NIL for the
- * pointers and 0 for the lengths.
- * This can be passed to Rpc_Reply */
- {
- SigParms *sigParmsPtr;
- ReturnStatus status;
- Proc_ControlBlock *procPtr;
- int effUid;
-
- sigParmsPtr = (SigParms *) storagePtr->requestParamPtr;
- procPtr = Proc_GetCurrentProc();
- effUid = procPtr->effectiveUserID;
- procPtr->effectiveUserID = sigParmsPtr->effUid;
- status = Sig_Send(sigParmsPtr->sigNum, sigParmsPtr->code, sigParmsPtr->id,
- sigParmsPtr->familyID, sigParmsPtr->addr);
- procPtr->effectiveUserID = effUid;
- Rpc_Reply(srvToken, status, storagePtr, (int(*)())NIL, (ClientData)NIL);
- return(SUCCESS);
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Sig_SetHoldMask --
- *
- * Set the signal hold mask for the current process. Return the
- * old mask. No synchronization required since the only process
- * that can modify the hold mask is this process.
- *
- * Results:
- * Error if the place to store the old mask is invalid, SUCCESS
- * otherwise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
- ReturnStatus
- Sig_SetHoldMask(newMask, oldMaskPtr)
- int newMask; /* Mask to set the hold mask to. */
- int *oldMaskPtr; /* Where to store the old mask. */
- {
- register Proc_ControlBlock *procPtr;
-
- /*
- * Get out the old mask value and store the new one.
- */
-
- procPtr = Proc_GetActualProc();
-
- if (oldMaskPtr != USER_NIL) {
- if (Vm_CopyOut(sizeof(procPtr->sigHoldMask),
- (Address) &(procPtr->sigHoldMask),
- (Address) oldMaskPtr) != SUCCESS) {
- return(SYS_ARG_NOACCESS);
- }
- }
-
- procPtr->sigHoldMask = newMask & sigCanHoldMask;
- procPtr->specialHandling = 1;
-
- return(SUCCESS);
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Sig_SetAction --
- *
- * Set the action for a particular signal.
- *
- * Results:
- * Error if the action, signal, or handler is invalid.
- *
- * Side effects:
- * The sigAction and sigMasks fields may be modified for the
- * particular signal.
- *
- *----------------------------------------------------------------------
- */
-
- ReturnStatus
- Sig_SetAction(sigNum, newActionPtr, oldActionPtr)
- int sigNum; /* The signal for which the action is to be
- set. */
- Sig_Action *newActionPtr; /* The actions to take for the signal. */
- Sig_Action *oldActionPtr; /* The action that was taken for the signal. */
- {
- Proc_ControlBlock *procPtr;
- Address dummy;
- Sig_Action action;
-
- /*
- * Make sure that the signal is in range.
- */
- if (sigNum < SIG_MIN_SIGNAL || sigNum >= SIG_NUM_SIGNALS ||
- sigNum == SIG_KILL || sigNum == SIG_SUSPEND) {
- return(SIG_INVALID_SIGNAL);
- }
-
- procPtr = Proc_GetActualProc();
-
- /*
- * Copy out the current action. There are two cases:
- *
- * 1) The current action really contains a handler to call. Thus
- * the current action is SIG_HANDLE_ACTION.
- * 2) The current action is one of the other four actions.
- */
-
- if (oldActionPtr != (Sig_Action *) USER_NIL) {
- if (procPtr->sigActions[sigNum] > SIG_NUM_ACTIONS) {
- action.action = SIG_HANDLE_ACTION;
- action.handler = (int (*)())procPtr->sigActions[sigNum];
- action.sigHoldMask = procPtr->sigMasks[sigNum];
- } else {
- if (procPtr->sigActions[sigNum] == sigDefActions[sigNum]) {
- action.action = SIG_DEFAULT_ACTION;
- } else {
- action.action = procPtr->sigActions[sigNum];
- }
- }
- if (Vm_CopyOut(sizeof(action), (Address) &action,
- (Address) oldActionPtr) != SUCCESS) {
- return(SYS_ARG_NOACCESS);
- }
- }
-
- /*
- * Copy in the action to take.
- */
-
- if (Vm_CopyIn(sizeof(action), (Address) newActionPtr,
- (Address) &action) != SUCCESS) {
- return(SYS_ARG_NOACCESS);
- }
-
- /*
- * Make sure that the action is valid.
- */
-
- if (action.action < 0 || action.action > SIG_NUM_ACTIONS) {
- return(SIG_INVALID_ACTION);
- }
-
- if (action.action == SIG_DEFAULT_ACTION) {
- action.action = sigDefActions[sigNum];
- }
-
- /*
- * Store the action. If it is SIG_HANDLE_ACTION then the handler is stored
- * in place of the action.
- */
-
- if (action.action == SIG_HANDLE_ACTION) {
- if (Vm_CopyIn(4, (Address) ((unsigned int) (action.handler)),
- (Address) &dummy) != SUCCESS) {
- return(SYS_ARG_NOACCESS);
- }
- procPtr->sigMasks[sigNum] =
- (sigBitMasks[sigNum] | action.sigHoldMask) & sigCanHoldMask;
- procPtr->sigActions[sigNum] = (unsigned int) action.handler;
- } else if (action.action == SIG_IGNORE_ACTION) {
-
- /*
- * Only actions that can be blocked can be ignored. This prevents a
- * user from ignoring a signal such as a bus error which would cause
- * the process to take a bus error repeatedly.
- */
-
- if (sigBitMasks[sigNum] & sigCanHoldMask) {
- procPtr->sigActions[sigNum] = SIG_IGNORE_ACTION;
- Proc_Lock(procPtr);
- SigClearPendingMask(procPtr, sigNum);
- if (sigNum == SIG_SUSPEND) {
- procPtr->genFlags &= ~(PROC_PENDING_SUSPEND |
- PROC_RESUME_PROCESS);
- }
- Proc_Unlock(procPtr);
- } else {
- return(SIG_INVALID_SIGNAL);
- }
- procPtr->sigMasks[sigNum] = 0;
- } else {
- procPtr->sigActions[sigNum] = action.action;
- procPtr->sigMasks[sigNum] = 0;
- }
-
- return(SUCCESS);
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Sig_Pause --
- *
- * Atomically change signal hold mask and wait for a signal to arrive.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
- ENTRY ReturnStatus
- Sig_Pause(sigHoldMask)
- int sigHoldMask; /* The value that the mask of held signals is to be set
- to while waiting for a signal to arrive. */
- {
- register Proc_ControlBlock *procPtr;
- ReturnStatus status;
- int migMask;
-
- LOCK_MONITOR;
-
- procPtr = Proc_GetActualProc();
-
- /*
- * The signal mask cannot be restored until the signal handler has
- * had a chance to be called for the signal that caused Sig_Pause
- * to return. To allow this the current hold mask is stored in the
- * proc table and the flag sigPause is set to be true to indicate that
- * the hold mask has to be restored after the signal handler has had a
- * chance to be called.
- */
-
- procPtr->oldSigHoldMask = procPtr->sigHoldMask;
- procPtr->sigFlags |= SIG_PAUSE_IN_PROGRESS;
- procPtr->sigHoldMask = sigHoldMask & sigCanHoldMask;
- procPtr->specialHandling = 1;
-
- /*
- * Wait on the signal condition. As it turns out since a signal
- * wakes up the process regardless what it is sleeping on, this condition
- * variable is never broadcasted on, but we have to wait on something in
- * order to release the monitor lock.
- *
- * Don't let a Sig_Pause be interrupted by a migrate trap signal.
- * So, if none of the signal bits are set besides migration-related
- * signals, and a migration-related signal bit is set, let the user-level
- * code retry the signal.
- */
- (void) Sync_Wait(&signalCondition, TRUE);
-
- migMask = (Sig_NumberToMask(SIG_MIGRATE_TRAP)) |
- (Sig_NumberToMask(SIG_MIGRATE_HOME));
- if ((! (procPtr->sigPendingMask & ~migMask)) &&
- (procPtr->sigPendingMask & migMask)) {
- status = GEN_ABORTED_BY_SIGNAL;
- } else {
- status = SUCCESS;
- }
-
- UNLOCK_MONITOR;
-
- return(status);
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * SigClearPendingMask --
- *
- * Remove the given signal from the pending mask.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Pending mask for process modified.
- *
- *----------------------------------------------------------------------
- */
-
- ENTRY void
- SigClearPendingMask(procPtr, sigNum)
- register Proc_ControlBlock *procPtr;
- int sigNum;
- {
- LOCK_MONITOR;
-
- procPtr->sigPendingMask &= ~sigBitMasks[sigNum];
-
- UNLOCK_MONITOR;
- }
-
- /*
- *---------------------------------------------------------------------------
- *
- * Routines for signal handlers --
- *
- * A signal handler is called right before a process is to return to
- * user space. In order to do this the current state before the signal
- * is taken must be saved, the signal handler called, and then the state
- * restored when the signal handler returns. It is this modules responsibility
- * to handle the signal state; all of the actual saving and restoring of
- * machine state and the calling of the handler is done in the machine
- * dependent routines in the mach module.
- */
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Sig_Handle --
- *
- * Set things up so that the signal handler is called for one of the
- * signals that are pending for the current process. This is done
- * by saving the old trap stack and modifying the current one.
- *
- * Results:
- * Return TRUE if a signal is setup to be handled by the user.
- *
- * Side effects:
- * *trapStackPtr is modified and also the user stack is modified.
- *
- *----------------------------------------------------------------------
- */
- Boolean
- Sig_Handle(procPtr, sigStackPtr, pcPtr)
- register Proc_ControlBlock *procPtr;
- register Sig_Stack *sigStackPtr;
- Address *pcPtr;
- {
- int sigs;
- int sigNum;
- unsigned int *bitMaskPtr;
- int sigBitMask;
-
- /*
- * Find out which signals are pending.
- */
- sigs = procPtr->sigPendingMask & ~procPtr->sigHoldMask;
- if (sigs == 0) {
- return(FALSE);
- }
-
- /*
- * Check for the signal SIG_KILL. This is processed specially because
- * it is how processes that have some problem such as being unable
- * to write to swap space on the file server are destroyed.
- */
- if (sigs & sigBitMasks[SIG_KILL]) {
- if (procPtr->sigCodes[SIG_KILL] != SIG_NO_CODE) {
- Proc_ExitInt(PROC_TERM_DESTROYED,
- procPtr->sigCodes[SIG_KILL], 0);
- } else {
- Proc_ExitInt(PROC_TERM_SIGNALED, SIG_KILL, 0);
- }
- }
-
- for (sigNum = SIG_MIN_SIGNAL, bitMaskPtr = &sigBitMasks[SIG_MIN_SIGNAL];
- !(sigs & *bitMaskPtr);
- sigNum++, bitMaskPtr++) {
- }
-
- SigClearPendingMask(procPtr, sigNum);
-
- /*
- * Process the signal.
- */
- switch (procPtr->sigActions[sigNum]) {
- case SIG_IGNORE_ACTION:
- printf("Warning: %s\n",
- "Sig_Handle: An ignored signal was in a signal pending mask.");
- return(FALSE);
-
- case SIG_KILL_ACTION:
- if (sigNum == SIG_KILL || !(procPtr->genFlags & PROC_DEBUGGED)) {
- Proc_ExitInt(PROC_TERM_SIGNALED, sigNum,
- procPtr->sigCodes[sigNum]);
- panic("Sig_Handle: Proc_Exit returned!\n");
- } else {
- /* Fall through */
- }
-
- case SIG_SUSPEND_ACTION:
- case SIG_DEBUG_ACTION:
- /*
- * A suspended process and a debugged process are basically
- * the same. A suspended process can be debugged just like
- * a process in the debug state. The only difference is that
- * a suspended process does not go onto the debug list; it can
- * only be debugged by a debugger that specifically asks for
- * it.
- *
- * Suspend the process.
- */
- Proc_SuspendProcess(procPtr,
- procPtr->sigActions[sigNum] == SIG_DEBUG_ACTION,
- PROC_TERM_SIGNALED, sigNum,
- procPtr->sigCodes[sigNum]);
- return(FALSE);
-
- case SIG_MIGRATE_ACTION:
- /*
- * If the process was in the middle of a page fault,
- * its PC in the trap stack is not useable.
- * Reset the pending condition but hold it until we get out of
- * the kernel.
- */
- if (!Mach_CanMigrate(procPtr)) {
- LocalSend(procPtr, sigNum, procPtr->sigCodes[sigNum],
- (Address)procPtr->sigAddr);
- procPtr->sigHoldMask |= Sig_NumberToMask(SIG_MIGRATE_TRAP);
- return(FALSE);
- }
-
- /*
- * Double-check against process not allowed to migrate. This
- * can happen if a process migrates, opens a pdev as master,
- * and gets signalled to migrate home.
- */
- if (procPtr->genFlags & PROC_DONT_MIGRATE) {
- if (proc_MigDebugLevel > 0) {
- printf("Proc_Migrate: process %x is not allowed to migrate.\n",
- procPtr->processID);
- }
- return(FALSE);
- }
- if (procPtr->peerHostID != NIL) {
- if (proc_MigDebugLevel > 6) {
- printf("Sig_Handle calling Proc_MigrateTrap for process %x.\n",
- procPtr->processID);
- }
- Proc_MigrateTrap(procPtr);
- }
- return(FALSE);
-
- case SIG_DEFAULT_ACTION:
- panic("Sig_Handle: SIG_DEFAULT_ACTION found in array of actions?\n");
- }
-
- /*
- * Set up our part of the signal stack.
- */
- sigStackPtr->sigNum = sigNum;
- sigStackPtr->sigCode = procPtr->sigCodes[sigNum];
- sigStackPtr->sigAddr = procPtr->sigAddr;
- /*
- * If this signal handler is being called after a call to Sig_Pause then
- * the real signal hold mask has to be restored after the handler returns.
- * This is assured by pushing the real hold mask which is stored in
- * the proc table onto the stack.
- */
- if (procPtr->sigFlags & SIG_PAUSE_IN_PROGRESS) {
- procPtr->sigFlags &= ~SIG_PAUSE_IN_PROGRESS;
- sigStackPtr->contextPtr->oldHoldMask = procPtr->oldSigHoldMask;
- } else {
- sigStackPtr->contextPtr->oldHoldMask = procPtr->sigHoldMask;
- }
-
- procPtr->sigHoldMask |= procPtr->sigMasks[sigNum];
- sigBitMask = sigBitMasks[sigNum];
- if (sigBitMask & ~sigCanHoldMask) {
- /*
- * If this is a non-blockable signal then add it to the hold mask
- * so that if we get it again we know that it can't be handled.
- */
- procPtr->sigHoldMask |= sigBitMask;
- }
- procPtr->specialHandling = 1;
- *pcPtr = (Address)procPtr->sigActions[sigNum];
- return(TRUE);
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Sig_Return --
- *
- * Process a return from signal.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The trap stack is modified.
- *
- *----------------------------------------------------------------------
- */
- void
- Sig_Return(procPtr, sigStackPtr)
- register Proc_ControlBlock *procPtr; /* Process that is returning
- * from a signal. */
- Sig_Stack *sigStackPtr; /* Signal stack. */
- {
- procPtr->sigHoldMask = sigStackPtr->contextPtr->oldHoldMask;
- procPtr->specialHandling = 1;
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Sig_AllowMigration --
- *
- * Set up a process to allow migration. This is a special call
- * because normally the SIG_MIGRATE_TRAP signal is not holdable in
- * the first place.
- *
- * This could be a macro and be called directly from
- * Mach_StartUserProc, once things are stable....
- *
- * Results:
- * None.
- *
- * Side effects:
- * The process's hold mask is modified.
- *
- *----------------------------------------------------------------------
- */
- void
- Sig_AllowMigration(procPtr)
- register Proc_ControlBlock *procPtr; /* process to modify */
- {
- if (procPtr->sigHoldMask &&
- (procPtr->sigHoldMask & sigBitMasks[SIG_MIGRATE_TRAP])) {
- procPtr->sigHoldMask &= ~sigBitMasks[SIG_MIGRATE_TRAP];
- procPtr->specialHandling = 1;
- }
- }
-
-
- /*
- *----------------------------------------------------------------------
- *
- * Sig_CheckForKill --
- *
- * Check if a process has a kill signal and kill it if so.
- * Otherwise return. this is for calling in difficult places where
- * we can't allow any signals that would be handled in user mode to
- * occur.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Process may be killed.
- *
- *----------------------------------------------------------------------
- */
- void
- Sig_CheckForKill(procPtr)
- Proc_ControlBlock *procPtr;
- {
- int sigs;
-
- /*
- * Find out which signals are pending.
- */
- sigs = procPtr->sigPendingMask & ~procPtr->sigHoldMask;
- if (sigs == 0) {
- return;
- }
-
- /*
- * Check for the signal SIG_KILL. This is processed specially because
- * it is how processes that have some problem such as being unable
- * to write to swap space on the file server are destroyed.
- */
- if (sigs & sigBitMasks[SIG_KILL]) {
- if (procPtr->sigCodes[SIG_KILL] != SIG_NO_CODE) {
- Proc_ExitInt(PROC_TERM_DESTROYED,
- procPtr->sigCodes[SIG_KILL], 0);
- } else {
- Proc_ExitInt(PROC_TERM_SIGNALED, SIG_KILL, 0);
- }
- }
- return;
- }
-